package com.test.recordaudio

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.media.MediaRecorder
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.io.File

class RecordService : Service() {

    companion object {
        const val ACTION_START = "start"
        const val ACTION_STOP = "stop"
        var isRecording = false
            private set

        fun start(context: Context) {
            context.applicationContext.let { app ->
                app.startService(Intent(app, RecordService::class.java).apply {
                    action = ACTION_START
                })
            }
        }

        fun stop(context: Context) {
            context.applicationContext.let { app ->
                app.startService(Intent(app, RecordService::class.java).apply {
                    action = ACTION_STOP
                })
            }
        }

    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    private val mediaRecorder by lazy {
        MediaRecorder()
    }

    private val mediaFile by lazy {
        File(cacheDir, "test.arm")
    }

    private var startTime = 0L
    private var timeJob: Job? = null
    private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            ACTION_START -> start()
            ACTION_STOP -> stop()
        }
        return super.onStartCommand(intent, flags, startId)
    }

    @SuppressLint("MissingPermission")
    private fun start() {
        isRecording = true
        if (mediaFile.exists()) {
            mediaFile.delete()
        }

        val notification = NotificationCompat.Builder(this, CHANNEL_NAME)
            .setContentTitle("正在录音")
            .setSmallIcon(R.mipmap.ic_launcher_round)
            .setAutoCancel(false)
            .setShowWhen(false)
            .setOngoing(true)

        val notificationManager = NotificationManagerCompat.from(this)

        reset()
        mediaRecorder.prepare()
        mediaRecorder.start()
        startTime = System.currentTimeMillis()

        // 立即显示前台服务
        notification.foregroundServiceBehavior = NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
        // 启动前台服务
        startForeground(1, notification.build())

        timeJob = serviceScope.launch {
            while (isRecording && isActive) {
                delay(1000)
                val notification2 = NotificationCompat.Builder(this@RecordService, CHANNEL_NAME)
                    .setContentTitle("正在录音: ${(System.currentTimeMillis() - startTime) / 1000}s")
                    .setSmallIcon(R.mipmap.ic_launcher_round)
                    .setAutoCancel(false)
                    .setShowWhen(false)
                    .setOngoing(true)
                    .build()
                notificationManager.notify(1, notification2)
            }
        }
    }

    private fun stop() {
        mediaRecorder.stop()
        isRecording = false
        timeJob?.cancel()

        stopForeground(STOP_FOREGROUND_REMOVE)
        stopSelf()
    }

    private fun reset() {
        with(mediaRecorder) {
            // 从麦克采集
            setAudioSource(MediaRecorder.AudioSource.MIC)
            // 保存为arm格式
            setOutputFormat(MediaRecorder.OutputFormat.AMR_NB)
            // 采样率
            setAudioSamplingRate(44100)
            // 编码格式
            setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
            // 音质频率
            setAudioEncodingBitRate(1024 * 1024)
            // 设置文件位置
            setOutputFile(mediaFile)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        serviceScope.cancel()
    }
}